﻿#include "FITKOCCModelSolid.h"
#include <gp_Pnt.hxx>
#include <gp_Dir.hxx>
#include <TopoDS.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepPrimAPI_MakeRevol.hxx>
#include <BRepPrimAPI_MakePrism.hxx>
#include <BRepOffset_MakeOffset.hxx>
#include <BRepOffsetAPI_MakePipe.hxx>
#include <BRepBuilderAPI_MakeShell.hxx>
#include <BRepBuilderAPI_MakeSolid.hxx>
#include <BRepBuilderAPI_Sewing.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopExp_Explorer.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <Precision.hxx>
#include <BRepBndLib.hxx>
#include <BRepOffsetAPI_ThruSections.hxx>

#include <TopoDS_Shape.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Wire.hxx>

#include <FITK_Interface/FITKInterfaceGeometry/FITKGeoEnum.h>
#include <FITK_Interface/FITKInterfaceGeometry/FITKVirtualTopoManager.h>
#include "FITKOCCVirtualTopoCreator.h"

#include "FITK_Kernel/FITKAppFramework/FITKAppFramework.h"
#include "FITK_Kernel/FITKAppFramework/FITKGlobalData.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoCommandList.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKGeoInterfaceFactory.h"
#include "FITK_Interface/FITKInterfaceGeometry/FITKAbsGeoModelSurface.h"

#include <FITKOCCModelCurve.h>

namespace {
    struct CWire {
        Bnd_Box Bound;
        BRepBuilderAPI_MakeWire MakeWire{};
        gp_Pnt Start{};
        gp_Pnt End{};
        bool isNull() { return MakeWire.Edge().IsNull(); }
        bool isClosed() { return MakeWire.Shape().Closed(); }
    };
}

namespace OCC
{
    FITKOCCModelClosedSurfaceSolid::FITKOCCModelClosedSurfaceSolid() : OCCShapeAgent(this)
    {
        _shapeAgent = _occShapeAgent;
    }
    bool FITKOCCModelClosedSurfaceSolid::update()
    {
        if (m_Faces.isEmpty()) return false;

        auto geoCmdList = FITKGLODATA->getGeometryData<Interface::FITKGeoCommandList>();

        BRepBuilderAPI_Sewing sewing;

        for (int i = 0; i < m_Faces.size(); ++i) {
            auto face = m_Faces.at(i);
            if (face.isNull()) continue;

            auto cmd = geoCmdList->getDataByID(face.CmdId);
            if (cmd == nullptr)
            {
                printLog(tr("Failed to get geometry command."), 3);
                return false;
            }
            auto vshape = cmd->getShapeT<FITKOCCTopoShape>(Interface::FITKGeoEnum::VTopoShapeType::VSFace, face.VirtualTopoId);
            if (vshape == nullptr)
            {
                printLog(tr("Failed to get face from virtual topo."), 3);
                return false;
            }
            auto topoShape = vshape->getTopoShape();
            if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_FACE) {
                TopoDS_Face f = TopoDS::Face(topoShape);
                if (f.IsNull()) continue;
                if (f.Orientation() == TopAbs_Orientation::TopAbs_REVERSED) {
                    f.Reverse();
                }
                sewing.Add(f);
            }
            else {
                printLog(tr("Error topo shape type for make wire."), 3);
                return false;
            }
        }
        sewing.Perform();

        auto type = sewing.SewedShape().ShapeType();

        /*if (type == TopAbs_COMPOUND)
        {
            TopoDS_Builder aShellBuilder;
            TopoDS_Shell aShell;

            aShellBuilder.MakeShell(aShell);

            int faceCount = 0;
            int edgeCount = 0;

            for (TopoDS_Iterator anExp(sewing.SewedShape()); anExp.More(); anExp.Next())
            {
                const TopoDS_Shape &curShape1 = anExp.Value();
                TopAbs_ShapeEnum type1 = curShape1.ShapeType();

                if (type1 == TopAbs_SHELL)
                {
                    for (TopExp_Explorer anExp(curShape1, TopAbs_FACE); anExp.More(); anExp.Next())
                    {
                        const TopoDS_Shape &curShape2 = anExp.Current();
                        aShellBuilder.Add(aShell, curShape2);
                        faceCount++;
                    }
                }
            }
        }*/

        if (type != TopAbs_SHELL)
        {
            printLog(tr("Error topo shape type for make wire."), 3);
            return false;
        }
        try {
            TopoDS_Shell shell = TopoDS::Shell(sewing.SewedShape());
            if (shell.IsNull() || !shell.Closed()) {
                printLog(tr("Must be closed shell."), 3);
                return false;
            }
            BRepBuilderAPI_MakeSolid solid(shell);

            if (!solid.IsDone()) {
                printLog(tr("Error topo shape type for make wire."), 3);
                return false;
            }
            _occShapeAgent->updateShape(solid.Shape());
        }
        catch (...)
        {
            printLog(tr("Failed to make solid!"), 3);
            return false;
        }
        return true;
    }



    FITKOCCModelExtrudeSolid::FITKOCCModelExtrudeSolid() : OCCShapeAgent(this)
    {
        _shapeAgent = _occShapeAgent;
    }
    bool FITKOCCModelExtrudeSolid::update()
    {

        auto geoCmdList = FITKGLODATA->getGeometryData<Interface::FITKGeoCommandList>();

        auto cmd = geoCmdList->getDataByID(m_SourceSurface.CmdId);
        if (cmd == nullptr) return false;

        Interface::FITKGeoEnum::VTopoShapeType type = cmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSFace;

        auto shape = cmd->getShapeT<FITKOCCTopoShape>(type, m_SourceSurface.VirtualTopoId);
        if (shape == nullptr) return false;

        auto topoShape = shape->getTopoShape();
        gp_Vec dir(m_Direction[0], m_Direction[1], m_Direction[2]);
        auto mag = dir.Magnitude();
        if (mag <= Precision::Confusion()) {
            printLog(tr("The direction cannot be a zero vector!"), 3);
            return false;
        }
        dir = dir * m_Length / mag;

        try {
            // 如果是草绘则返回的是线的组合体，需要合并面
            if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND)
            {
                TopoDS_Compound compound = TopoDS::Compound(topoShape);
                TopExp_Explorer exp;


                QList<CWire> wiresList{};

                // 按封闭曲线分组
                for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next())
                {
                    TopoDS_Edge edge = TopoDS::Edge(exp.Current());
                    if (edge.IsNull()) continue;

                    Standard_Real first;
                    Standard_Real last;
                    Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last);
                    gp_Pnt start = curve->Value(first);
                    gp_Pnt end = curve->Value(last);

                    /* 自成封闭的曲线 */
                    /* @{ */
                    if (start.Distance(end) < Precision::Confusion()) {
                        CWire w;
                        w.MakeWire.Add(edge);
                        w.Start = start;
                        w.End = end;
                        wiresList.push_back(w);
                        continue;
                    }
                    /* @} */

                    /* 是否能拼接到已有曲线 */
                    /* @{ */
                    bool isSep{ true };
                    for (auto& wire : wiresList) {
                        // 已经闭合的曲线不参与比较
                        if (wire.isClosed()) continue;
                        if (wire.Start.Distance(start) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.Start = end;
                            isSep = false;
                            break;
                        }
                        else if (wire.Start.Distance(end) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.Start = start;
                            isSep = false;
                            break;
                        }
                        else if (wire.End.Distance(start) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.End = end;
                            isSep = false;
                            break;
                        }
                        else if (wire.End.Distance(end) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.End = start;
                            isSep = false;
                            break;
                        }
                        else {
                            printLog(QString("wire.Start: [%1, %2, %3]; wire.End: [%4, %5, %6]").arg(wire.Start.X()).arg(wire.Start.Y()).arg(wire.Start.Z()).arg(wire.End.X()).arg(wire.End.Y()).arg(wire.End.Z()), 2);
                            printLog(QString("Start: [%1, %2, %3]; End: [%4, %5, %6]").arg(start.X()).arg(start.Y()).arg(start.Z()).arg(end.X()).arg(end.Y()).arg(end.Z()), 2);
                        }
                    }
                    /* @} */

                    // 如果能连接到已有曲线，则分析下一条边
                    if (!isSep) continue;
                    // 如果不能连接到已有曲线，则自成一条新的曲线
                    else {
                        CWire w;
                        w.MakeWire.Add(edge);
                        w.Start = start;
                        w.End = end;
                        wiresList.push_back(w);
                        continue;
                    }
                }
                // 检测封闭性，计算包围盒
                for (auto wire : wiresList) {
                    if (!wire.isClosed()) {
                        printLog(tr("The selected sketch contains several open profile."), 3);
                        return false;
                    }
                    else {
                        BRepBndLib::Add(wire.MakeWire.Shape(), wire.Bound);
                    }
                }
                /* 按包围盒大小排序 */
                /* @{ */
                for (int i = 0; i < wiresList.size() - 1; ++i) {
                    int n = i;
                    while (n >= 0 && wiresList.at(n).Bound.IsOut(wiresList.at(n + 1).Bound)) {
                        auto temp = wiresList.at(n);
                        wiresList[n] = wiresList[n + 1];
                        wiresList[n + 1] = temp;
                        n--;
                    }
                }
                /* @} */

                // 初始化组合对象。
                BRep_Builder builder;
                TopoDS_Compound compoundSolid;
                builder.MakeCompound(compoundSolid);

                auto count = wiresList.size();
                for (int i = 0; i < count; ++i) {
                    auto wire = wiresList.at(i);
                    BRepBuilderAPI_MakeFace face(wire.MakeWire, true);
                    if (count > i + 1) {
                        CWire cwire = wiresList.at(i + 1);
                        TopoDS_Shape innerShape = cwire.MakeWire.Shape();
                        if (innerShape.ShapeType() != TopAbs_WIRE) return false;
                        TopoDS_Wire innerWire = TopoDS::Wire(innerShape);
                        if (innerWire.IsNull()) return false;
                        innerWire.Reverse();
                        face.Add(innerWire);
                        ++i;
                    }
                    face.Build();
                    if (!face.IsDone()) return false;
                    builder.Add(compoundSolid, BRepPrimAPI_MakePrism(face, dir).Shape());
                }

                _occShapeAgent->updateShape(compoundSolid);
            }
            else {
                _occShapeAgent->updateShape(BRepPrimAPI_MakePrism(topoShape, dir).Shape());
            }
        }
        catch (...)
        {
            printLog(tr("Failed to make solid!"), 3);
            return false;
        }
        return true;
    }
    FITKOCCModelRevolSolid::FITKOCCModelRevolSolid() : OCCShapeAgent(this)
    {
        _shapeAgent = _occShapeAgent;
    }
    bool FITKOCCModelRevolSolid::update()
    {
        auto geoCmdList = FITKGLODATA->getGeometryData<Interface::FITKGeoCommandList>();

        auto cmd = geoCmdList->getDataByID(m_SourceSurface.CmdId);
        if (cmd == nullptr) return false;

        Interface::FITKGeoEnum::VTopoShapeType type = cmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSFace;

        auto vshape = cmd->getShapeT<FITKOCCTopoShape>(type, m_SourceSurface.VirtualTopoId);
        if (vshape == nullptr) return false;
        auto topoShape = vshape->getTopoShape();
        //m_OriginId;
        gp_Ax1 ax1(
            gp_Pnt(m_RotateAxisPoint1[0], m_RotateAxisPoint1[1], m_RotateAxisPoint1[2]),
            gp_Dir(m_RotateAxisPoint2[0] - m_RotateAxisPoint1[0], m_RotateAxisPoint2[1] - m_RotateAxisPoint1[1], m_RotateAxisPoint2[2] - m_RotateAxisPoint1[2]));
        try {
            // 如果是草绘则返回的是线的组合体，需要合并面
            if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND)
            {
                TopoDS_Compound compound = TopoDS::Compound(topoShape);
                TopExp_Explorer exp;


                QList<CWire> wiresList{};

                // 按封闭曲线分组
                for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next())
                {
                    TopoDS_Edge edge = TopoDS::Edge(exp.Current());
                    if (edge.IsNull()) continue;

                    Standard_Real first;
                    Standard_Real last;
                    Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last);
                    gp_Pnt start = curve->Value(first);
                    gp_Pnt end = curve->Value(last);

                    /* 自成封闭的曲线 */
                    /* @{ */
                    if (start.Distance(end) < Precision::Confusion()) {
                        CWire w;
                        w.MakeWire.Add(edge);
                        w.Start = start;
                        w.End = end;
                        wiresList.push_back(w);
                        continue;
                    }
                    /* @} */

                    /* 是否能拼接到已有曲线 */
                    /* @{ */
                    bool isSep{ true };
                    for (auto& wire : wiresList) {
                        // 已经闭合的曲线不参与比较
                        if (wire.isClosed()) continue;
                        if (wire.Start.Distance(start) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.Start = end;
                            isSep = false;
                            break;
                        }
                        else if (wire.Start.Distance(end) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.Start = start;
                            isSep = false;
                            break;
                        }
                        else if (wire.End.Distance(start) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.End = end;
                            isSep = false;
                            break;
                        }
                        else if (wire.End.Distance(end) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.End = start;
                            isSep = false;
                            break;
                        }
                        else {
                            printLog(QString("wire.Start: [%1, %2, %3]; wire.End: [%4, %5, %6]").arg(wire.Start.X()).arg(wire.Start.Y()).arg(wire.Start.Z()).arg(wire.End.X()).arg(wire.End.Y()).arg(wire.End.Z()), 2);
                            printLog(QString("Start: [%1, %2, %3]; End: [%4, %5, %6]").arg(start.X()).arg(start.Y()).arg(start.Z()).arg(end.X()).arg(end.Y()).arg(end.Z()), 2);
                        }
                    }
                    /* @} */

                    // 如果能连接到已有曲线，则分析下一条边
                    if (!isSep) continue;
                    // 如果不能连接到已有曲线，则自成一条新的曲线
                    else {
                        CWire w;
                        w.MakeWire.Add(edge);
                        w.Start = start;
                        w.End = end;
                        wiresList.push_back(w);
                        continue;
                    }
                }
                // 检测封闭性，计算包围盒
                for (auto wire : wiresList) {
                    if (!wire.isClosed()) {
                        printLog(tr("The selected sketch contains several open profile."), 3);
                        return false;
                    }
                    else {
                        BRepBndLib::Add(wire.MakeWire.Shape(), wire.Bound);
                    }
                }
                /* 按包围盒大小排序 */
                /* @{ */
                for (int i = 0; i < wiresList.size() - 1; ++i) {
                    int n = i;
                    while (n >= 0 && wiresList.at(n).Bound.IsOut(wiresList.at(n + 1).Bound)) {
                        auto temp = wiresList.at(n);
                        wiresList[n] = wiresList[n + 1];
                        wiresList[n + 1] = temp;
                        n--;
                    }
                }
                /* @} */

                // 初始化组合对象。
                BRep_Builder builder;
                TopoDS_Compound compoundSolid;
                builder.MakeCompound(compoundSolid);

                auto count = wiresList.size();
                for (int i = 0; i < count; ++i) {
                    auto wire = wiresList.at(i);
                    BRepBuilderAPI_MakeFace face(wire.MakeWire, true);
                    if (count > i + 1) {
                        CWire cwire = wiresList.at(i + 1);
                        TopoDS_Shape innerShape = cwire.MakeWire.Shape();
                        if (innerShape.ShapeType() != TopAbs_WIRE) return false;
                        TopoDS_Wire innerWire = TopoDS::Wire(innerShape);
                        if (innerWire.IsNull()) return false;
                        innerWire.Reverse();
                        face.Add(innerWire);
                        ++i;
                    }
                    face.Build();
                    if (!face.IsDone()) return false;
                    builder.Add(compoundSolid, BRepPrimAPI_MakeRevol(face, ax1, m_Angle  * M_PI / 180).Shape());
                }

                _occShapeAgent->updateShape(compoundSolid);
            }
            else {
                _occShapeAgent->updateShape(BRepPrimAPI_MakeRevol(topoShape, ax1, m_Angle  * M_PI / 180).Shape());
            }
        }
        catch (...)
        {
            printLog(tr("Failed to make solid!"), 3);
            return false;
        }
        return true;
    }
    FITKOCCModelSweepSolid::FITKOCCModelSweepSolid() : OCCShapeAgent(this)
    {
        _shapeAgent = _occShapeAgent;
    }
    bool FITKOCCModelSweepSolid::update()
    {
        auto geoCmdList = FITKGLODATA->getGeometryData<Interface::FITKGeoCommandList>();

        auto profileCmd = geoCmdList->getDataByID(m_Profile.CmdId);
        auto curveCmd = geoCmdList->getDataByID(m_Curve.CmdId);
        if (profileCmd == nullptr || curveCmd == nullptr) return false;

        Interface::FITKGeoEnum::VTopoShapeType profileType = profileCmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSFace;
        auto profileShape = profileCmd->getShapeT<FITKOCCTopoShape>(profileType, m_Profile.VirtualTopoId);

        Interface::FITKGeoEnum::VTopoShapeType curveType = curveCmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSEdge;
        auto curveShape = curveCmd->getShapeT<FITKOCCTopoShape>(curveType, m_Curve.VirtualTopoId);
        if (profileShape == nullptr || curveShape == nullptr) return false;

        auto profileTopoShape = profileShape->getTopoShape();
        auto curveTopoShape = curveShape->getTopoShape();

        try {
            /* 分析扫略线 */
            /*@{*/
            TopoDS_Wire sweepWire;
            auto type = curveTopoShape.ShapeType();
            if (type == TopAbs_ShapeEnum::TopAbs_WIRE)
            {
                sweepWire = TopoDS::Wire(curveTopoShape);
            }
            else if (type == TopAbs_ShapeEnum::TopAbs_EDGE) {
                sweepWire = BRepBuilderAPI_MakeWire(TopoDS::Edge(curveTopoShape));
            }
            else if (type == TopAbs_ShapeEnum::TopAbs_COMPOUND) {
                TopoDS_Compound compound = TopoDS::Compound(curveTopoShape);
                TopExp_Explorer exp;
                BRepBuilderAPI_MakeWire makeWire;
                for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next())
                {
                    TopoDS_Edge edge = TopoDS::Edge(exp.Current());
                    if (edge.IsNull()) continue;
                    makeWire.Add(edge);
                }
                makeWire.Build();
                if (!makeWire.IsDone()) return false;
                sweepWire = TopoDS::Wire(makeWire.Shape());
            }
            else return false;
            /*@}*/


            // 如果是草绘则返回的是线的组合体，需要合并面
            if (profileTopoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND)
            {
                TopoDS_Compound compound = TopoDS::Compound(profileTopoShape);
                TopExp_Explorer exp;


                QList<CWire> wiresList{};

                // 按封闭曲线分组
                for (exp.Init(compound, TopAbs_EDGE); exp.More(); exp.Next())
                {
                    TopoDS_Edge edge = TopoDS::Edge(exp.Current());
                    if (edge.IsNull()) continue;

                    Standard_Real first;
                    Standard_Real last;
                    Handle(Geom_Curve) curve = BRep_Tool::Curve(edge, first, last);
                    gp_Pnt start = curve->Value(first);
                    gp_Pnt end = curve->Value(last);

                    /* 自成封闭的曲线 */
                    /* @{ */
                    if (start.Distance(end) < Precision::Confusion()) {
                        CWire w;
                        w.MakeWire.Add(edge);
                        w.Start = start;
                        w.End = end;
                        wiresList.push_back(w);
                        continue;
                    }
                    /* @} */

                    /* 是否能拼接到已有曲线 */
                    /* @{ */
                    bool isSep{ true };
                    for (auto& wire : wiresList) {
                        // 已经闭合的曲线不参与比较
                        if (wire.isClosed()) continue;
                        if (wire.Start.Distance(start) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.Start = end;
                            isSep = false;
                            break;
                        }
                        else if (wire.Start.Distance(end) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.Start = start;
                            isSep = false;
                            break;
                        }
                        else if (wire.End.Distance(start) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.End = end;
                            isSep = false;
                            break;
                        }
                        else if (wire.End.Distance(end) < Precision::Confusion())
                        {
                            wire.MakeWire.Add(edge);
                            wire.End = start;
                            isSep = false;
                            break;
                        }
                        else {
                            printLog(QString("wire.Start: [%1, %2, %3]; wire.End: [%4, %5, %6]").arg(wire.Start.X()).arg(wire.Start.Y()).arg(wire.Start.Z()).arg(wire.End.X()).arg(wire.End.Y()).arg(wire.End.Z()), 2);
                            printLog(QString("Start: [%1, %2, %3]; End: [%4, %5, %6]").arg(start.X()).arg(start.Y()).arg(start.Z()).arg(end.X()).arg(end.Y()).arg(end.Z()), 2);
                        }
                    }
                    /* @} */

                    // 如果能连接到已有曲线，则分析下一条边
                    if (!isSep) continue;
                    // 如果不能连接到已有曲线，则自成一条新的曲线
                    else {
                        CWire w;
                        w.MakeWire.Add(edge);
                        w.Start = start;
                        w.End = end;
                        wiresList.push_back(w);
                        continue;
                    }
                }
                // 检测封闭性，计算包围盒
                for (auto wire : wiresList) {
                    if (!wire.isClosed()) {
                        printLog(tr("The selected sketch contains several open profile."), 3);
                        return false;
                    }
                    else {
                        BRepBndLib::Add(wire.MakeWire.Shape(), wire.Bound);
                    }
                }
                /* 按包围盒大小排序 */
                /* @{ */
                for (int i = 0; i < wiresList.size() - 1; ++i) {
                    int n = i;
                    while (n >= 0 && wiresList.at(n).Bound.IsOut(wiresList.at(n + 1).Bound)) {
                        auto temp = wiresList.at(n);
                        wiresList[n] = wiresList[n + 1];
                        wiresList[n + 1] = temp;
                        n--;
                    }
                }
                /* @} */

                // 初始化组合对象。
                BRep_Builder builder;
                TopoDS_Compound compoundSolid;
                builder.MakeCompound(compoundSolid);

                auto count = wiresList.size();
                for (int i = 0; i < count; ++i) {
                    auto wire = wiresList.at(i);
                    BRepBuilderAPI_MakeFace face(wire.MakeWire, true);
                    if (count > i + 1) {
                        CWire cwire = wiresList.at(i + 1);
                        TopoDS_Shape innerShape = cwire.MakeWire.Shape();
                        if (innerShape.ShapeType() != TopAbs_WIRE) return false;
                        TopoDS_Wire innerWire = TopoDS::Wire(innerShape);
                        if (innerWire.IsNull()) return false;
                        innerWire.Reverse();
                        face.Add(innerWire);
                        ++i;
                    }
                    face.Build();
                    if (!face.IsDone()) return false;
                    builder.Add(compoundSolid, BRepOffsetAPI_MakePipe(sweepWire, face).Shape());
                }

                _occShapeAgent->updateShape(compoundSolid);
            }
            else {
                BRepOffsetAPI_MakePipe pipe(sweepWire, profileTopoShape);
                pipe.Build();
                if (!pipe.IsDone()) return false;
                _occShapeAgent->updateShape(pipe.Shape());
            }
            return true;
        }
        catch (...)
        {
            printLog(tr("Failed to make solid!"), 3);
            return false;
        }
    }

    FITKOCCModelMultiSectionSolid::FITKOCCModelMultiSectionSolid() : OCCShapeAgent(this)
    {
        _shapeAgent = _occShapeAgent;
    }

    bool FITKOCCModelMultiSectionSolid::update()
    {
        if (m_Sections.size() < 2) return false;

        auto geoCmdList = FITKGLODATA->getGeometryData<Interface::FITKGeoCommandList>();

        BRepOffsetAPI_ThruSections thruSection(true);

        for (auto section : m_Sections) {
            auto cmd = geoCmdList->getDataByID(section.CmdId);
            if (cmd == nullptr) return false;
            Interface::FITKGeoEnum::VTopoShapeType type = cmd->getGeometryCommandType() == Interface::FITKGeoEnum::FITKGeometryComType::FGTSketch2D ? Interface::FITKGeoEnum::VTopoShapeType::VSAssembly : Interface::FITKGeoEnum::VTopoShapeType::VSEdge;
            auto vshape = cmd->getShapeT<FITKOCCTopoShape>(type, section.VirtualTopoId);
            if (vshape == nullptr) return false;
            auto topoShape = vshape->getTopoShape();

            if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_EDGE) {
                BRepLib_MakeWire wire(TopoDS::Edge(topoShape));
                thruSection.AddWire(wire.Wire());
            }
            else if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_WIRE) {
                thruSection.AddWire(TopoDS::Wire(topoShape));
            }
            else if (topoShape.ShapeType() == TopAbs_ShapeEnum::TopAbs_COMPOUND) {
                TopExp_Explorer exp;
                BRepLib_MakeWire wire;
                // 按封闭曲线分组
                for (exp.Init(topoShape, TopAbs_EDGE); exp.More(); exp.Next())
                {
                    TopoDS_Edge edge = TopoDS::Edge(exp.Current());
                    if (edge.IsNull()) continue;
                    wire.Add(edge);
                }
                try
                {
                    wire.Build();
                    if (!wire.IsDone()) return false;
                    thruSection.AddWire(wire.Wire());
                }
                catch (...)
                {
                    printLog(tr("Failed to make wire!"), 3);
                    return false;
                }
            }
        }

        try {
            thruSection.Build();
            if (!thruSection.IsDone()) return false;
            _occShapeAgent->updateShape(thruSection.Shape());
        }
        catch (...)
        {
            printLog(tr("Failed to make solid!"), 3);
            return false;
        }
        return true;
    }

}
